// 实现这个项目的构建任务

// 引入各种模块
const { src, dest, parallel, series, watch } = require("gulp");
const plugins = require("gulp-load-plugins")();
const browserSync = require("browser-sync").create();
const fs = require("fs-extra");
const { program } = require("commander");
const { exec } = require("child_process");
const { promisify } = require("util");

// 通过commander简化命令行操作
program.option("--port <port>").option("--open").option("--production").option("--prod");
program.parse(process.argv);

let isProd = program.production || program.prod

// eslint任务，执行构建操作之前需要运行，如果有错就不执行后续任务
const lint = () =>
  src("src/assets/scripts", { base: "src" })
    .pipe(plugins.eslint())
    .pipe(plugins.eslint.format())
    .pipe(plugins.eslint.failAfterError());

// html任务，传入自定义data并编译模板
const html = () =>
  src("src/**/*.html", { base: "src" })
    .pipe(
      plugins.swig({
        defaults: { cache: false }, // 此处需要关闭缓存
        data: {
          date: new Date(),
          pkg: require("./package.json"),
          menus: [
            {
              name: "Home",
              icon: "aperture",
              link: "index.html",
            },
            {
              name: "Features",
              link: "features.html",
            },
            {
              name: "About",
              link: "about.html",
            },
            {
              name: "Contact",
              link: "#",
              children: [
                {
                  name: "Twitter",
                  link: "https://twitter.com/w_zce",
                },
                {
                  name: "About",
                  link: "https://weibo.com/zceme",
                },
                {
                  name: "divider",
                },
                {
                  name: "About",
                  link: "https://github.com/zce",
                },
              ],
            },
          ],
        },
      })
    )
    .pipe(dest("temp"));

// html模板编译完毕后清除目录
const cleanTemplate = () =>
  Promise.all([fs.remove("temp/layouts"), fs.remove("temp/partials")]);

// 编译sass
const css = () =>
  src("src/assets/styles/**", { base: "src" })
    .pipe(plugins.sass())
    .pipe(dest("temp"));

// 编译js
const script = () =>
  src("src/assets/scripts/**", { base: "src" })
    .pipe(plugins.babel())
    .pipe(dest("temp"));

// 压缩图片
const image = () =>
  src("src/assets/images/**", { base: "src" })
    .pipe(plugins.imagemin())
    .pipe(dest("dist"));

// 压缩字体
const font = () =>
  src("src/assets/fonts/**", { base: "src" })
    .pipe(plugins.imagemin())
    .pipe(dest("dist"));

// 复制静态文件
const extra = () => src("public/**", { base: "public" }).pipe(dest("temp"));

// 复制asset
const copyAsset2Dist = () => src("src/assets/**", { base: "src" }).pipe(dest("dist"))

// 清除临时目录
const cleanTemp = () => fs.remove("temp");

// 清除目标目录
const cleanDist = () => fs.remove("dist");

// 清除部署目录
const cleanPages = () => fs.remove("../../pages");

// 组合任务：编译html、css、js
const compile = parallel(series(html, cleanTemplate), css, script);

// 组合任务：压缩字体、图片
const asset = parallel(image, font);

// 组合任务：清除临时、目标目录
const clean = parallel(cleanTemp, cleanDist);

// 组合引用文件
const useref = () =>
  src("temp/*.html", { base: "temp" })
    .pipe(plugins.useref({ searchPath: ["temp", "."] }))
    .pipe(plugins.if(isProd && /\.js$/, plugins.uglifyEs.default())) // 这里用uglify不行，得用uglify-es
    .pipe(plugins.if(isProd && /\.css$/, plugins.cleanCss()))
    .pipe(
      plugins.if(
        /\.html$/,
        plugins.htmlmin({
          collapseWhitespace: isProd,
          minifyCSS: isProd,
          minifyJS: isProd,
        })
      )
    )
    .pipe(dest("dist"));

// 启动服务器
const serve = () => {
  const workDir = isProd ? "dist" : "temp"; // 根据环境确定监听目录
  watch(
    ["src/assets/fonts/**", "src/assets/images/**", "public/**"],
    browserSync.reload
  );
  watch("src/assets/styles", css);
  watch("src/assets/scripts", script);
  watch("src/*.html", html);
  return browserSync.init({
    notify: !isProd,
    open: program.open,
    port: program.port || 3000,
    files: `${workDir}/**`,
    server: {
      baseDir: [workDir, "src", "public"],
      routes: {
        "/node_modules": "node_modules",
      },
    },
  });
};

// 将temp中的内容拷贝到根目录dist文件夹
const copyTemp2Dist = () => src("temp/**").pipe(dest("dist"));

// 组合任务：开发服务器下build
const buildTemp = series(lint, clean, parallel(compile, extra));

// 组合任务：生产环境下静态build
const buildProd = series(lint, clean, parallel(compile, asset, extra));

// 组合任务：开发环境下静态build
const build = isProd ? series(buildProd, useref, cleanTemp) : series(clean, buildTemp, copyTemp2Dist, copyAsset2Dist, cleanTemp);

// 将dist中的内容拷贝到根目录pages文件夹
const copy2pages = () => src("dist/**").pipe(dest("../../pages"));

// 提交pages代码到git
const publish2gitee = () =>
  promisify(exec)(
    `git add ../../pages && git commit -m "publish pages" && git push origin master`
  );

// 组合任务：生成静态文件后，清理pages文件夹，复制dist到pages中，最后发布pages
const deploy = series(build, cleanPages, copy2pages, publish2gitee);

// 生产环境下服务器
const start = () => {
  isProd = true
  return series(lint, build, serve)();
};
module.exports = {
  build,
  compile,
  deploy,
  clean,
  serve: series(lint, buildTemp, serve),
  start,
  lint,
  default: start,
};
